﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Net;
using System.IO;
using System.Text.RegularExpressions;
using VSDBM.Code.dao;
using VSDBM.Code.dto;
using System.Threading;
using System.Text;
using System.Data;
using System.Xml;
using System.Xml.Serialization;

namespace VSDBM.Code.functions
{
    public class zeseeker
    {
        static int idOrganism;
        static eFetchSeq.eUtilsServiceSoapClient serv2 = new eFetchSeq.eUtilsServiceSoapClient();
        static int tfinish;
        static int tdownloaded;
        static int terror;
        static int added;
        static int badSequence;
        int userid;

        public static int getQnt(string organism)
        {
            int qnt=0;
            
            String url2 = "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=nuccore&term=";
            url2 = url2 += organism.Replace(" ", "+");
            url2 = url2 += "&rettype=count";
            WebClient wc2 = new WebClient();
            String resultado = "";
            try
            {
              resultado = wc2.DownloadString(url2);
              wc2.Dispose();
            }
            catch (Exception exp)
            {
               throw exp;
            }
            if (resultado != "")
                {
                    String[] aux3 = Regex.Split(resultado, "<Count>");
                    String[] aux4 = Regex.Split(aux3[1], "</Count>");
                    qnt = Convert.ToInt32(aux4[0]);
                    
                    return qnt;
                }
                else
                {
                    
                    return qnt;
                    
                }

        }

        public static string getOrganism(string id, string banco)
        {
            
            String url = "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=";
            url += banco + "&id=";
            url += id;
            url += "&rettype=gb&retmode=xml";
            String resultado = "";
            WebClient wc = new WebClient();
            try
            {
                resultado = wc.DownloadString(url);
                wc.Dispose();
            }
            catch (Exception exp)
            {
                throw exp;
            }
            if (resultado != "")
            {
                String[] aux = Regex.Split(resultado, "<GBSeq_organism>");
                if (aux.Length == 2)
                {
                    String[] aux2 = Regex.Split(aux[1], "</GBSeq_organism>");
                    String organism = aux2[0];
                    return organism;
                }
                else
                {
                    return resultado;
                }

            }
            else
            {
                return "";

            }



        }

        public static bool checkOrganism(String Organism)
        {
            DataSet ds = OrganismDAO.select("WHERE name='" + Organism + "'", "");
            try 
	          {
                  
                      if (ds == null || ds.Tables[0].Rows.Count == 0)
                      {
                          return false;
                      }
                      else
                      {
                          return true;
                      }
                  
                  
	          }
	        catch (Exception)
	          {
		
	        	      throw;
	          }
            
        }

        public static void setOrganism(String Organism)
        {
           
                DataSet ds = OrganismDAO.select("WHERE name='" + Organism + "'", "");
                if (ds.Tables[0].Rows.Count > 0)
                {
                    int status = Convert.ToInt32(ds.Tables[0].Rows[0][2]);
                    if (status == 0)
                    {
                        OrganismDAO.setActive(Convert.ToInt32(ds.Tables[0].Rows[0][0]));
                    }
                    idOrganism = Convert.ToInt32(ds.Tables[0].Rows[0][0]);
                }
                else
                {
                    Exception exp = new Exception("Organism not found in database. Please, verify that the first sequence in XML have the same OrganismName added in database.");
                    throw exp; 
                }
        }

        public static String GetIdList(String organismName, String db, int qnt)
        {
            String IdList = "";
            StringBuilder builder = new StringBuilder();
            String url2 = "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=";
            url2 += db + "&term=";
            url2 += organismName.Replace(" ", "+");
            url2 += "&retstart=0&retmax=" + Convert.ToString(qnt);
            WebClient wc2 = new WebClient();
            DataSet ds = new DataSet();
            ds.ReadXml(wc2.OpenRead(url2));
            foreach (DataRow row in ds.Tables[2].Rows)
            {

                    builder.Append(row[0]);
                    builder.Append(",");
            }
            IdList = builder.ToString();
            return IdList;
            
        }

        public void executeeSearch(string id,string organism, string db, int userid)
        {
            int qnt = getQnt(organism);
            if (!checkOrganism(organism))
            {
                Exception ex = new Exception("Organism not found!");
                throw ex;
            }
            else
            {
                eUtils.eUtilsServiceSoapClient serv = new eUtils.eUtilsServiceSoapClient();
                eUtils.eSearchRequest req = new eUtils.eSearchRequest();
                req.db = db;
                req.term = organism.Replace(" ", "+");
                req.RetStart = "0";
                req.usehistory = "y";
                req.field = "Organism";
                eUtils.eSearchResult res = new eUtils.eSearchResult();
                try
                {
                    res = serv.run_eSearch(req);
                }
                catch (Exception e)
                {

                    throw e;
                }
                setOrganism(organism);
                this.userid = userid;
                executeeFetch(qnt, res.WebEnv, res.QueryKey, db);
                // executeeFetchPOST(qnt, res.WebEnv, res.QueryKey, db);
                // executeeFetchFILE(qnt, res.WebEnv, res.QueryKey, db);
            }
        }

        public void executeeFetch(int qnt, string webEnv, string queryKey, string db)
        {
            int start = 0;

            while (start < qnt)
            { 
                eFetchSeq.eFetchRequest req = new eFetchSeq.eFetchRequest();
                req.complexity = "3";
                req.db = db;
                req.query_key = queryKey;
                req.WebEnv = webEnv;
                req.retstart  = Convert.ToString(start);
                req.retmax = "9000";
                eFetchSeq.eFetchResult res = new eFetchSeq.eFetchResult();
                try
                {
                     res = serv2.run_eFetch(req);
                    tdownloaded++;
                }
                catch (Exception e)
                {


                    start = start - 9000;
                }

                taddDados(res, userid);
            
            
                start = start + 9000;
            }
            while (added < qnt)
            {
                Thread.Sleep(300);
            }
            
            

        }

        public void taddDados(Object resn, int userid)
        {
            eFetchSeq.eFetchResult res = resn as eFetchSeq.eFetchResult;
            foreach (eFetchSeq.GBSeq seq in res.GBSet.GBSeq)
            {
                if (seq.GBSeq_accessionversion!=null)
                {
                    Sequence sequence = new Sequence(0, seq.GBSeq_definition, seq.GBSeq_accessionversion, idOrganism, 0, userid, seq.GBSeq_locus, seq.GBSeq_sequence, Convert.ToInt32(seq.GBSeq_length), 0);
                    try
                    {
                        SequenceDAO.add(sequence);
                        added++;
                    }
                    catch (Exception e)
                    {
                        added++;
                    }

                    
                }
                else
                {
                    badSequence++;
                }
            }
            tfinish++;
        }

        public static void executeeFetchPOST(int qnt, string webEnv, string queryKey, string db)
        {
            int start = 0;
            while (start < qnt)
            {

            String URL = "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=";
            URL += db + "&query_key=";
            URL += queryKey;
            URL +="&WebEnv=";
            URL += webEnv ;
            URL +="&retstart="+Convert.ToString(start);
            URL+= "&retmax=500&complexity=3&rettype=gb&retmode=xml";
            WebClient wc2 = new WebClient();
            System.Uri andress = new Uri(URL);
            DataSet ds = new DataSet();
            ds.ReadXml(wc2.OpenRead(URL));
            if (ds.Tables[0].TableName == "GBSeq")
            {
                foreach (System.Data.DataRow dado in ds.Tables[0].Rows)
                {
                    if (dado[10].ToString()!= "")
                    {
                    SequenceDAO.add(new Sequence(1, dado["GBSeq_definition"].ToString(), dado["GBSeq_accession-version"].ToString(), idOrganism, 1, 1, dado["GBSeq_locus"].ToString(), dado["GBSeq_sequence"].ToString(), Convert.ToInt32(dado["GBSeq_length"]), 1));
                    added++;
                    }
                    else
                    {
                        badSequence++;
                    }

                }


                start = start + 500;
            }
            else
            {
                terror++;
            }
            
            }
            added = 0;


        }

        public static Sequence runSingleeFetchPOST(string id, string db)
        {
            Sequence seq = new Sequence();
            try
            {

                String URL = "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=";
                URL += db;
                URL += "&id=" + id;
                URL += "&complexity=3&rettype=gb&retmode=xml";
                WebClient wc2 = new WebClient();
                System.Uri andress = new Uri(URL);
                DataSet ds = new DataSet();
                String xml = wc2.DownloadString(URL);
                ds.ReadXml(wc2.OpenRead(URL));
                if (ds.Tables[0].TableName == "GBSeq")
                {
                    foreach (DataRow row in ds.Tables[0].Rows)
                    {

                        seq = new Sequence(1, row["GBSeq_definition"].ToString(), row["GBSeq_accession-version"].ToString(), idOrganism, 1, 1, row["GBSeq_locus"].ToString(), row["GBSeq_sequence"].ToString(), Convert.ToInt32(row["GBSeq_length"]), 1);
                        return seq;
                        
                    }
                }
                else
                {
                    runSingleeFetchPOST(id, db);
                }
                
            }
            catch (Exception)
            {

                throw;
            }

            return seq;
        }


        public static List<object> getReferenceSequencePOST(string id, string db)
        {
            List<object> lista = new List<object>();
            Sequence seq = new Sequence();
            List<Reference_Feature> listadefeatures = new List<Reference_Feature>();
            try
            {

                String URL = "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=";
                URL += db;
                URL += "&id=" + id;
                URL += "&complexity=3&rettype=gb&retmode=xml";
                WebClient wc2 = new WebClient();
                System.Uri andress = new Uri(URL);
                DataSet ds = new DataSet();
                String xml = wc2.DownloadString(URL);
                ds.ReadXml(wc2.OpenRead(URL));
                if (ds.Tables[0].TableName == "GBSeq")
                {
                    foreach (DataRow row in ds.Tables["GBSeq"].Rows)
                    {

                        seq = new Sequence(1, row["GBSeq_definition"].ToString(), row["GBSeq_accession-version"].ToString(), idOrganism, 1, 1, row["GBSeq_locus"].ToString(), row["GBSeq_sequence"].ToString(), Convert.ToInt32(row["GBSeq_length"]), 1);
                        lista.Add(seq);
                        for (int x = 0; x < ds.Tables["GBFeature"].Rows.Count; x++)
                        {
                            if (x > 0)
                            {
                                Reference_Feature feature = new Reference_Feature();
                                feature.featurekey = Convert.ToString(ds.Tables["GBFeature"].Rows[x][0]);
                                foreach (DataRow positionalinfo in ds.Tables["GBInterval"].Rows)
                                {
                                    if (Convert.ToInt32(positionalinfo[3]) == x)
                                    {
                                        feature.positionInitial = Convert.ToInt32(positionalinfo[0]);
                                        feature.positionFinal = Convert.ToInt32(positionalinfo[1]);
                                    }
                                }
                                foreach (DataRow qualifierinfo in ds.Tables["GBQualifier"].Rows) 
                                {
                                  if(Convert.ToInt32(qualifierinfo[2]) == x)
                                  {
                                      feature.name = Convert.ToString(qualifierinfo[0]);
                                      feature.description = Convert.ToString(qualifierinfo[1]);
                                  }
                                }
                                listadefeatures.Add(feature);
                            }
                        }
                        lista.Add(listadefeatures);
                        return lista;

                    }
                }
                else
                {
                    runSingleeFetchPOST(id, db);
                }

            }
            catch (Exception)
            {

                throw;
            }

            return lista;
        }
        

        public static void executeeSearchPOST(string id, string organism, string db)
        {
            int qnt = getQnt(organism);
            setOrganism(organism);
            String url2 = "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=";
            url2 += db+"&term=";
            url2 += organism.Replace(" ", "+");
            url2 += "&retstart=0&retmax=" + Convert.ToString(qnt);
            WebClient wc2 = new WebClient();
            DataSet ds = new DataSet();
            string xml = wc2.DownloadString(url2);
            ds.ReadXml(wc2.OpenRead(url2));
            int count =0;

            List<string[]> report = new List<string[]>();
            while(count < qnt)
            {
                string[] vetor = new string[2];
                StringBuilder builder = new StringBuilder();
                if (qnt >= 100)
                {
                    for (int x = 0; x <= 100; x++)
                    {
                        builder.Append(ds.Tables[2].Rows[x+count][0]);
                        if (x < 100)
                        {
                            builder.Append(",");
                        }
                    }
                    count = count + 100;
                }
                else
                {
                    for (int x = 0; x < qnt; x++)
                    {
                        builder.Append(ds.Tables[2].Rows[x+count][0]);
                        if (x != qnt - 1)
                        {
                            builder.Append(",");
                        }
                    }
                    count = count + qnt;
                }
                string metaid = builder.ToString();
                vetor[0]= metaid;
                vetor[1] = Convert.ToString(runSingleeFetchPOST(metaid, db));
                report.Add(vetor);
                
            }

        }

        public static void insertFromFile(DataTable table, int iduser)
        {
            String Organism = Convert.ToString(table.Rows[0][13]);
            try
            {
                setOrganism(Organism);
            }
            catch (Exception)
            {
                throw;
            }
            try
            {
                foreach (DataRow row in table.Rows)
                {
                    Sequence seq = new Sequence(1, row["INSDSeq_definition"].ToString(), row["INSDSeq_accession-version"].ToString(), idOrganism, 1, iduser, row["INSDSeq_locus"].ToString(), row["INSDSeq_sequence"].ToString(), Convert.ToInt32(row["INSDSeq_length"]), 0);
                    SequenceDAO.add(seq);
                }
            }
            catch (Exception exps)
            {
                
                throw exps;
            }
            
        }
                
    }
}